接下來這幾天,會開始逐一說明要怎麼順利地取得要放入使用手冊的截圖,今天會先從「定位元件」開始討論。
如果是用 Day 05 的流程圖來說,差不多是這個部分:
如果大家有寫過測試或是爬蟲,應該會知道「定位元件」是一個麻煩的事情。通常只能利用 CSS class name 或是 XPath 來定位 (在某些時候也可以考慮直接用 text),但是這幾個做法都不太穩定,很容易因為前端版本更新就讓定位失效了。
對於失效原因,稍微講細一點:
- CSS class name:在許多 React 專案中會使用 CSS-in-JS 工具(例如 styled-components、Emotion)或 CSS Modules 這類方案,它們會在 class 後面帶上一段雜湊值。這個雜湊通常跟樣式內容或建置流程綁定,一旦程式碼或樣式有異動、重新 build,雜湊值就可能跟著改變,不能拿來當穩定的定位依據。
- XPath:它記錄的是 DOM 結構的位置,因此只要結構改變 (e.g. 多加一層
<div>),它就失效了。- text:也就是畫面上顯示的文字,基本上只要換語言就會失效。
最理想的做法,是使用 id 這種唯一的屬性,因為它天生具備唯一性,不會像 class 那樣容易因為樣式或建置流程而變動。如果對象是自己公司的產品,這件事做起來也不難,只要請前端工程師 (或是其實就是你自己) 幫忙,在要定位的元件上加上 id 就可以了,技術上完全可行。
不過,實務上通常不會直接拿 id 來定位,而是會另外加一個 data-testid 屬性。原因在於 id 往往已經另有用途,例如綁定 CSS 樣式、給 JavaScript 操作 DOM、或是做錨點跳轉;一旦前端工程師之後因為改樣式或重構程式碼動到這些 id,測試就會跟著遭殃。data-testid 則是一個「專門為測試而生」的屬性,語意上就宣告了「這個屬性只給測試用,其他人不要動」,前端工程師在重構時也會刻意避開它,穩定性自然比直接用 id 高上不少。
光靠 data-testid 存在還不夠,如果命名混亂一樣會讓維護變成災難。我個人比較偏好的做法是這個格式:
區域-元件功能
nav-tab_setting (導覽列的設定分頁)overview-add-node (總覽頁的新增節點按鈕)add-select-dialog (新增選擇對話框)這樣寫的好處很明顯,只要看一眼,就可以大致猜出元件在哪個位置、有什麼用途,不需要再回去對照原始碼。需要注意的是,盡量不要用 index 這種可能會因為排序、篩選而改變的東西。
最後,將這整套規範完整地寫成一份 TESTID.md 放在 Repo 中,可以給人類參考,也可以放入 AI Agent 上下文中,讓它知道該怎麼設計。
如果專案已經有一定規模,回頭補 data-testid 是一件頗麻煩的事情。不過,老話一句,反正現在有 AI Agent,問題並不大。只是在呼叫 AI Agent 補 data-testid 時,建議依照頁面處理,並準備好 TESTID.md 規範文件,接著再人工審核改動 (i.e. git diff)。
後續有頁面時,能順手補上 data-testid 是最理想的,不過,就算真的漏掉了,用先前的做法再請 AI Agent 補齊,也是可行的,問題不大。
雖然前面一直在吹捧 data-testid 這個方法有多實用,但還是難免有些需要注意的地方。

舉例來說,某些 UI 框架的 <Button> 元件,如果沒有特別設計「透傳(pass-through)未知 attribute」的機制,寫在 <Button data-testid="submit"> 上的屬性,可能根本不會出現在最終渲染出來的 <button> DOM 節點上。
遇到「selector 抓不到」的第一直覺,不該是去改 selector 的寫法,而是先打開瀏覽器的開發者工具,確認這個屬性到底有沒有出現在真正的 DOM 裡。
有些元件只在特定狀態下才會被 mount,例如:在某個 tab 在被選中之前 (i.e. 沒被選過),內容根本不存在於 DOM 裡,而不是只是被隱藏。此時不管 selector 寫得多準確都找不到,遇到這種狀況時要記得先確保前置狀態已經完成 (e.g. 每個 tab 都選過一遍)。
讓 UI 元件看不到的方法有很多種,常見的包含:display:none、visibility:hidden、opacity:0,以及直接拿其他元素覆蓋在上面 (z-index)。Playwright 對這幾種情況的判定不完全一樣:
display:none 跟 visibility:hidden 會讓 Playwright 認定元件不可見而等待逾時opacity:0 的元件在 Playwright 眼中通常仍視為可見data-testid雖然我們是精準定位元件的目的是製作使用手冊,但是這套操作應用程式的做法,其實也可以用在測試上 (尤其是 E2E 測試)。一個方法可以用在兩個地方,甚至有可能測試團隊已經處理好了,可以直接用,聽起來很不錯對吧?後續其他產線實作的內容,大家也可以順便思考看看,它對測試是否也有幫助XD

今天就先到這邊了,明天會繼續介紹其他實作細節!